﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BaseDomainNamespace.Builders
{
    /// <summary>
    /// エンティティビルダの基本クラスです。
    /// </summary>
    /// <remarks>
    /// <para>
    /// エンティティビルダは、エンティティの構築を行います。
    /// エンティティビルダの実装方法の詳細については <see cref="EntityBuilder&lt;TEntity, TErrorHandler, TConstraintValidator&gt;"/> クラスを参照してください。
    /// </para>
    /// </remarks>
    /// <typeparam name="TEntity">エンティティの型。</typeparam>
    /// <typeparam name="TErrorHandler">エラーハンドラの型。</typeparam>
    /// <seealso cref="IEntityBuilder&lt;TEntity&gt;"/>
    /// <seealso cref="EntityBuilder&lt;TEntity, TErrorHandler, TConstraintValidator&gt;"/>
    [Serializable]
    public abstract class EntityBuilder<TEntity, TErrorHandler> : IEntityBuilder<TEntity>
        where TEntity : class
        where TErrorHandler : class
    {
        /// <summary>
        /// エンティティの作成を目的として、<see cref="EntityBuilder&lt;TEntity, TErrorHandler&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        public EntityBuilder()
        {
        }

        /// <summary>
        /// エンティティの編集を目的として、<see cref="EntityBuilder&lt;TEntity, TErrorHandler&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="target">編集対象のエンティティ。</param>
        /// <exception cref="System.ArgumentNullException">target が null です。</exception>
        public EntityBuilder(TEntity target)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            _target = target;
        }


        /// <summary>
        /// 編集対象のエンティティ。
        /// </summary>
        private readonly TEntity _target;


        /// <summary>
        /// 編集対象のエンティティを取得します。
        /// </summary>
        /// <exception cref="System.InvalidOperationException">ビルダは作成を目的としています。</exception>
        protected TEntity Target
        {
            get
            {
                if (IsForCreation)
                {
                    throw new InvalidOperationException("ビルダは作成を目的としています。");
                }
                return _target;
            }
        }

        /// <summary>
        /// ビルダが作成を目的としているかどうかを示す値を取得します。
        /// </summary>
        /// <returns>ビルダが作成を目的としている場合は true、それ以外は false。</returns>
        protected bool IsForCreation
        {
            get
            {
                return (_target == null);
            }
        }

        /// <summary>
        /// ビルダが編集を目的としているかどうかを示す値を取得します。
        /// </summary>
        /// <returns>ビルダが編集を目的としている場合は true、それ以外は false。</returns>
        protected bool IsForEdition
        {
            get
            {
                return (_target != null);
            }
        }

        /// <summary>
        /// ビルドを実行できる状態であるかどうかを示す値を取得します。
        /// </summary>
        /// <returns>ビルドを実行できる状態である場合は true、それ以外は false。</returns>
        public bool IsValid
        {
            get
            {
                var errorFinder = new ErrorFinder<TErrorHandler>();
                NotifyErrorTo(errorFinder.GetAgent());
                return !errorFinder.Found;
            }
        }


        /// <summary>
        /// ビルダの現在のエラーを通知します。エラーが無い場合はハンドラには何も通知されません。
        /// </summary>
        /// <param name="handler">エラーハンドラ。</param>
        /// <exception cref="System.ArgumentNullException">handler が null です。</exception>
        public abstract void NotifyErrorTo(TErrorHandler handler);

        /// <summary>
        /// エンティティをビルドします。
        /// </summary>
        /// <returns>ビルドされたエンティティ。</returns>
        /// <exception cref="System.InvalidOperationException">エンティティをビルドできる状態ではありません。</exception>
        public abstract TEntity Build();
    }
}
